
package com.huaweicloud.saaslanding.install.applicationservice.impl;

import com.huaweicloud.saaslanding.basic.enumeration.ComponentLabelEnum;
import com.huaweicloud.saaslanding.basic.enumeration.ServiceManageFrameTypeEnum;
import com.huaweicloud.saaslanding.basic.utils.ConfigNameUtil;
import com.huaweicloud.saaslanding.basic.utils.RegexUtil;
import com.huaweicloud.saaslanding.dao.common.entity.deployedresource.CseResource;
import com.huaweicloud.saaslanding.huawei.nacos.api.NacosConfigApi;
import com.huaweicloud.saaslanding.huawei.nacos.api.NacosNamespaceApi;
import com.huaweicloud.saaslanding.install.applicationservice.CseResourceService;
import com.huaweicloud.saaslanding.install.dto.ServiceManageFrameworkDto;
import com.huaweicloud.saaslanding.install.json.ServiceManageFrameworkRequestBody;
import com.huaweicloud.saaslanding.install.properties.Nacos;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;

import java.util.List;

/**
 * Nacos相关操作
 *
 * @since 2022-10-26
 */
@Slf4j
public class NacosServiceImpl extends AbstractServiceManageFrameServiceImpl {
    @Resource
    private ServiceManageFrameworkRequestBody serviceManageFrameworkRequestBody;

    @Resource
    private CseResourceService cseResourceService;

    @Resource
    private Nacos nacos;

    @Override
    public void createServiceManageFrameConfig(ServiceManageFrameworkDto serviceManageFrameworkDto) {
        log.info("========== start: 创建 nacos 基础配置项 : {} ==========", serviceManageFrameworkDto.getServiceName());

        String configAddress = RegexUtil.ofHttp(nacos.getNacosServers().get(0));
        String namespace = nacos.getNamespace();
        String serviceName = serviceManageFrameworkDto.getServiceName();
        String appName = serviceManageFrameworkDto.getAppName();
        String active = serviceManageFrameworkDto.getActive();

        // 基础配置
        String basicDataId =
            createBasicConfig(serviceManageFrameworkDto, configAddress, namespace, serviceName, appName);

        // 网关动态路由配置
        String dynamicRouteDataId =
            createDynamicRoute(configAddress, namespace, serviceName, appName, serviceManageFrameworkDto);

        // 单微服务灰度配置
        String grayRouteDataId = createGrayRoute(configAddress, namespace, serviceName, appName, active);

        // 全链路灰度配置
        String dynamicRouteLinkDataId =
            createDynamicRouteLink(configAddress, namespace, appName, serviceManageFrameworkDto);

        // 落库
        cseResourceService.saveCseResource(serviceManageFrameworkDto, basicDataId, grayRouteDataId, dynamicRouteDataId,
            dynamicRouteLinkDataId, ServiceManageFrameTypeEnum.NACOS.getName());
    }

    /**
     * 创建全链路灰度配置文件
     *
     * @param configAddress 配置中心地址
     * @param namespaceId 命名空间
     * @param appName 注册应用名
     * @param serviceManageFrameworkDto 服务管理框架
     * @return Data Id
     */
    private String createDynamicRouteLink(String configAddress, String namespaceId, String appName,
        ServiceManageFrameworkDto serviceManageFrameworkDto) {

        String dynamicRouteLinkDataId = "";

        if (ComponentLabelEnum.GATEWAY.getLabel().equals(serviceManageFrameworkDto.getLabel())) {
            dynamicRouteLinkDataId = ConfigNameUtil.getDynamicRouteLink();

            // 创建dynamic-route-link配置
            NacosConfigApi.publish(configAddress, namespaceId, dynamicRouteLinkDataId, appName,
                serviceManageFrameworkRequestBody.initDynamicRouteLinkValue());
        }
        return dynamicRouteLinkDataId;
    }

    /**
     * 所有服务基础配置
     *
     * @param serviceManageFrameworkDto
     * @param configAddress
     * @param namespaceId
     * @param serviceName
     * @param appName
     * @return
     */
    private String createBasicConfig(ServiceManageFrameworkDto serviceManageFrameworkDto, String configAddress,
        String namespaceId, String serviceName, String appName) {
        // 公共配置文件
        String basicDataId = ConfigNameUtil.getBasic(serviceManageFrameworkDto.getActive(), serviceName);

        // 获取content信息
        String content = serviceManageFrameworkRequestBody.createNacosBasicConfigJson(serviceManageFrameworkDto);

        // 创建basic配置
        NacosConfigApi.publish(configAddress, namespaceId, basicDataId, appName, content);
        return basicDataId;
    }

    /**
     * 单微服务灰度配置
     *
     * @param configAddress
     * @param namespaceId
     * @param serviceName
     * @param appName
     * @param active
     * @return
     */
    private String createGrayRoute(String configAddress, String namespaceId, String serviceName, String appName,
        String active) {

        String grayRouteDataId = ConfigNameUtil.getGrayRoute(active, serviceName);
        log.info("========== end: 创建 nacos 单微服务灰度配置项 : {} ==========", serviceName);

        // 创建gray-route配置
        NacosConfigApi.publish(configAddress, namespaceId, grayRouteDataId, appName,
            serviceManageFrameworkRequestBody.initGrayRouteValue(ServiceManageFrameTypeEnum.NACOS.getName()));

        return grayRouteDataId;
    }

    /**
     * 创建网关的动态路由配置
     *
     * @param configAddress
     * @param namespaceId
     * @param serviceName
     * @param appName
     * @param serviceManageFrameworkDto
     * @return
     */
    private String createDynamicRoute(String configAddress, String namespaceId, String serviceName, String appName,
        ServiceManageFrameworkDto serviceManageFrameworkDto) {

        String dynamicRouteDataId = StrUtil.EMPTY;

        if (ComponentLabelEnum.GATEWAY.getLabel().equals(serviceManageFrameworkDto.getLabel())) {
            log.info("========== end: 创建 nacos 网关动态路由配置项 : {} ==========", serviceName);
            dynamicRouteDataId = ConfigNameUtil.getDynamicRoute(serviceManageFrameworkDto.getActive(), serviceName);

            // 创建dynamic-route配置
            NacosConfigApi.publish(configAddress, namespaceId, dynamicRouteDataId, appName,
                serviceManageFrameworkRequestBody.initDynamicRouteValue(serviceManageFrameworkDto));
        }
        return dynamicRouteDataId;
    }

    @Override
    public void deleteAllConfig() {
        log.info("========== start: 删除 所有 Nacos 配置文件 ==========");

        // 获取所有数据库中保存的配置项id
        List<CseResource> cseResourceList = cseResourceService.lambdaQuery()
            .eq(CseResource::getType, ServiceManageFrameTypeEnum.NACOS.getName())
            .list();

        if (CollectionUtil.isEmpty(cseResourceList)) {
            log.info("========== end: 没有需要删除的 NACOS 配置文件 ==========");
            return;
        }

        // 删除各微服务配置文件
        cseResourceList.forEach(this::deleteConfigByResource);

        // 删除命名空间
        NacosNamespaceApi.delete(RegexUtil.ofHttp(nacos.getNacosServers().get(0)),
            cseResourceList.get(0).getNamespaceId());
        log.info("========== end: 删除 所有 NACOS 配置文件 ==========");
    }

    /**
     * 删除微服务配置文件
     *
     * @param cseResource
     */
    private void deleteConfigByResource(CseResource cseResource) {
        String appName = cseResource.getAppName();
        String basicKvId = cseResource.getBasicKvId();
        String grayRouteKvId = cseResource.getGrayRouteKvId();
        String dynamicRouteKvId = cseResource.getDynamicRouteKvId();
        String dynamicRouteLinkKvId = cseResource.getDynamicRouteLinkKvId();
        String address = RegexUtil.ofHttp(nacos.getNacosServers().get(0));
        String namespaceId = nacos.getNamespace();

        if (StringUtils.isNotBlank(basicKvId)) {
            NacosConfigApi.delete(address, namespaceId, basicKvId, appName);
        }
        if (StringUtils.isNotBlank(grayRouteKvId)) {
            NacosConfigApi.delete(address, namespaceId, grayRouteKvId,
                appName);
        }
        if (StringUtils.isNotBlank(dynamicRouteKvId)) {
            NacosConfigApi.delete(address, namespaceId, dynamicRouteKvId,
                appName);
        }
        if (StringUtils.isNotBlank(dynamicRouteLinkKvId)) {
            NacosConfigApi.delete(address, namespaceId, dynamicRouteLinkKvId,
                appName);
        }

        // 库中删除数据
        cseResourceService.removeById(cseResource.getId());
    }
}
